using System;
using System.Xml.Serialization;

namespace SharpMud.MudLib.SAMPLE.Environment
{
	[XmlRoot("SimpleDirectionalExit")]
	public class SimpleDirectionalExit : IDescribableExit
	{
		#region Private Variables
		private RoomID			_TargetRoom;
		private bool			_IsObvious;
		private bool			_IsObtrusive;
		private string[]		_Keywords;
		private ExitDirection	_Direction;

		private string			_DeclarativeShortDescription;
		private string			_IntegralShortDescription;
		private string			_LongDescription;
		private string			_ShortDescription;
		#endregion
		
		#region Constructors
		public SimpleDirectionalExit()
		{
		}

		public SimpleDirectionalExit(ExitDirection direction, RoomID targetRoom)
		{
			if(targetRoom==null)
				throw new ArgumentNullException("targetRoom");

			this._Direction = direction;
			this._TargetRoom = targetRoom;
			this._IsObvious = true;
			this._IsObtrusive = false;
		}
		#endregion
		
		#region Public Properties
		[XmlElement("Direction")]
		public ExitDirection	Direction
		{
			get
			{
				return _Direction;
			}
			set
			{
				if(_Direction!=value)
				{
					_Direction = value;
					_Keywords = ExitDirectionKeywordsAttribute.FindKeywordsForDirection(value);
				}
				else
					return;
			}
		}

		#endregion

		#region IDescribableExit Members
		public bool IsObviousTo(SharpMud.MudLib.SAMPLE.Entities.ICharacter actor)
		{
			return this.IsObvious;
		}

		public bool IsObtrusiveTo(SharpMud.MudLib.SAMPLE.Entities.ICharacter actor)
		{
			return this.IsObtrusive;
		}
		#endregion

		#region IExit Members

		#region Basic Properties
		/// <summary>
		/// The room that this exit goes to
		/// </summary>
		[XmlElement("TargetRoom")]
		public RoomID	TargetRoom
		{
			get
			{
				return _TargetRoom;
			}
			set
			{
				this._TargetRoom = value;
			}
		}

		/// <summary>
		/// Whether or not this exit is obvious
		/// </summary>
		[XmlElement("IsObvious")]
		public bool IsObvious
		{
			get
			{
				return this._IsObvious;
			}
			set
			{
				this._IsObvious = value;
			}
		}

		/// <summary>
		/// Whether or not this exit is "obtrusive". If True, the exit is liste using the exit's
		/// short description. If False, the exit is listed using its target's room's short description.
		/// </summary>
		[XmlElement("IsObtrusive")]
		public bool IsObtrusive
		{
			get
			{
				return this._IsObtrusive;
			}
			set
			{
				this._IsObtrusive = value;
			}
		}
		#endregion

		[XmlIgnore]
		public string[] UsageKeyphrases
		{
			get
			{
				if(this._Keywords==null)
				{
					this._Keywords = ExitDirectionKeywordsAttribute.FindKeywordsForDirection(this._Direction);
				}
				return this._Keywords;
			}
		}

		public bool IsImmediatelyUsableTo(SharpMud.MudLib.SAMPLE.Entities.ICharacter actor)
		{
			return true;
		}

		public bool AttemptUsageBy(SharpMud.MudLib.SAMPLE.Entities.ICharacter actor)
		{
			//throw new NotImplementedException();
			// TODO:  Improve DirectionalExit.AttemptUsageBy implementation

			if(this.IsImmediatelyUsableTo(actor))
			{
				lock(actor)
				{
					lock(actor.Location.Room)
					{
						Environment.Room oldRoom = actor.Location.Room;
						actor.Location.Room.DeregisterCharacterFromHere(actor);
						//TOFIX: Only tell players that can see the character leaving
						//TOFIX: Tell all characters, not just players
						foreach(Entities.PlayerCharacter pc in oldRoom.GetCharactersHere())
						{
							Messaging.Act.IActMessage msg = new Messaging.Act.BuiltIn.Movement.Directional.Departure.ToWitness(actor,pc,this.Direction);
							pc.Session.WriteLine(msg);
						}
					}
					//TOFIX: Tell the *character* actors, not just the *players*
					if(actor is Entities.PlayerCharacter)
					{
						Messaging.Act.IActMessage msg = new Messaging.Act.BuiltIn.Movement.Directional.Departure.ToActor(actor,this.Direction);
						(actor as Entities.PlayerCharacter).Session.WriteLine(msg);
					}
					actor.Location = this.TargetRoom;
					lock(actor.Location.Room)
					{
						actor.Location.Room.RegisterCharacterHere(actor);
						//TOFIX: Only tell players that can see the character arriving
						//TOFIX: Tell all characters, not just players
						foreach(Entities.PlayerCharacter pc in actor.Location.Room.GetCharactersHere())
						{
							if(pc==actor)
								continue;
							Messaging.Act.IActMessage msg = new Messaging.Act.BuiltIn.Movement.Directional.Arrival.ToWitness(actor,pc,Environment.ReverseExitDirectionAttribute.GetReverseExitDirection(this.Direction));
							pc.Session.WriteLine(msg);
						}
					}
					//TOFIX: Only look if autolook is on - or - just do autolook and let autolook handle it
					if(actor is Entities.PlayerCharacter)
					{
						Entities.PlayerCharacter pactor = (Entities.PlayerCharacter)actor;
						pactor.HostServerApp.CommandManager.ExecuteCommand(actor,actor,"look");
					}
				}
				return true;
			}
			else
			{
				//The player could not use the exit.
				//Why?
				return false;
			}
		}

		#endregion

		#region Description-Related Properties
		[XmlElement("ShortDescription")]
		public string ShortDescription
		{
			get
			{
				return this._ShortDescription;
			}
			set
			{
				this._ShortDescription = value;
			}
		}
		
		[XmlElement("DeclarativeShortDescription")]
		public string DeclarativeShortDescription
		{
			get
			{
				return this._DeclarativeShortDescription;
			}
			set
			{
				this._DeclarativeShortDescription = value;
			}
		}
		
		[XmlElement("IntegralShortDescription")]
		public string IntegralShortDescription
		{
			get
			{
				return this._IntegralShortDescription;
			}
			set
			{
				this._IntegralShortDescription = value;
			}
		}
		
		[XmlElement("LongDescription")]
		public string LongDescription
		{
			get
			{
				return this._LongDescription;
			}
			set
			{
				this._LongDescription = value;
			}
		}
		#endregion

		#region IDescribable Members

		public string GetShortDescription(SharpMud.MudLib.SAMPLE.Entities.ICharacter looker)
		{
			return this.ShortDescription;
		}

		public string GetDeclarativeShortDescription(SharpMud.MudLib.SAMPLE.Entities.ICharacter looker)
		{
			return this.DeclarativeShortDescription;
		}

		public string GetIntegralShortDescription(SharpMud.MudLib.SAMPLE.Entities.ICharacter looker)
		{
			return this.IntegralShortDescription;
		}

		public string GetLongDescription(SharpMud.MudLib.SAMPLE.Entities.ICharacter looker)
		{
			return this.LongDescription;
		}

		#endregion

        #region IDisposable Members

        public void Dispose()
        {
            this._TargetRoom = null;
            this._Keywords = null;
        }

        #endregion
    }
}
